package com.jfree.nettyshow.server;

import com.jfree.nettyshow.common.CommonConstant;
import com.jfree.nettyshow.common.SessionManager;
import com.jfree.nettyshow.common.SpringUtil;
import com.jfree.nettyshow.handler.OutHand;
import com.jfree.nettyshow.handler.ServerTaskHandler;
import com.jfree.nettyshow.handler.TestHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.CharsetUtil;

import java.util.concurrent.TimeUnit;

/**
 * 待优化：对象用完回收，快速gc，解除用完对象的相互的绑定关系 ， 优雅关闭连接，清理不需要的(对象)内存
 * ssl安全，鉴权认证，白名单，session完善，netty系统配置参数优化（包括启动时的可传入的参数配置）
 * <p>
 * 待开发：动态传入参数的class也能正常处理,心跳机制，断开和重连机制
 */
public class Server {


    public void bind(int port) throws Exception {
        bind(port, 1, 4);

    }

    public void bind(int port, int bossThreadNum, int workThreadNum) throws Exception {
        EventLoopGroup boss = new NioEventLoopGroup(bossThreadNum);
        EventLoopGroup work = new NioEventLoopGroup(workThreadNum);
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        ServerTaskHandler handler = new ServerTaskHandler(SpringUtil.getBean(SessionManager.class));
        serverBootstrap.group(boss, work)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)//TODO 设置option
                .option(ChannelOption.SO_KEEPALIVE, true) //TODO 设置option
                .option(ChannelOption.TCP_NODELAY, true)

//   todo    childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); ?? netty 写的时候高低水位什么意思，iswriteable（）？？？
//        bootstrap.childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024);
                .handler(new LoggingHandler(LogLevel.INFO))
                .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new IdleStateHandler(0, 0, 0, TimeUnit.SECONDS));
                        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(
                                CommonConstant.MAX_BYTE_NUM, 0, 4, 0, 4));
                        ch.pipeline().addLast(new LengthFieldPrepender(4));
                        ch.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                        ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
                        ch.pipeline().addLast(handler);
                        ch.pipeline().addLast(new OutHand());
                        ch.pipeline().addLast(new TestHandler());
                        //todo 还需要考虑发送时和读取时的异常处理，做好方案
                    }
                });
        try {
            ChannelFuture f = serverBootstrap.bind(port).sync();
            System.out.println("----netty server启动成功----");
            f.channel().closeFuture().sync();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            boss.shutdownGracefully(); //TODO 这里做成close
            work.shutdownGracefully();
        }
    }
}
